{ *************************************************************************** }

 { Audio Tools Library                                                         }
 { Class TDTS - for manipulating with DTS Files                                }

 { http://mac.sourceforge.net/atl/                                             }
 { e-mail: macteam@users.sourceforge.net                                       }

{ Copyright (c) 2005 by Gambit                                                }

 { Version 1.1 (April 2005) by Gambit                                          }
 {   - updated to unicode file access                                          }

{ Version 1.0 (10 January 2005)                                               }

 { This library is free software; you can redistribute it and/or               }
 { modify it under the terms of the GNU Lesser General Public                  }
 { License as published by the Free Software Foundation; either                }
 { version 2.1 of the License, or (at your option) any later version.          }

 { This library is distributed in the hope that it will be useful,             }
 { but WITHOUT ANY WARRANTY; without even the implied warranty of              }
 { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           }
 { Lesser General Public License for more details.                             }

 { You should have received a copy of the GNU Lesser General Public            }
 { License along with this library; if not, write to the Free Software         }
 { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   }

{ *************************************************************************** }

unit DTS;

interface

uses
  Classes, SysUtils, TntClasses;

const
  BIRATES: array[0..31] of integer = (32, 56, 64, 96, 112, 128, 192, 224, 256,
    320, 384, 448, 512, 576, 640, 768, 960,
    1024, 1152, 1280, 1344, 1408, 1411, 1472,
    1536, 1920, 2048, 3072, 3840, 0, -1, 1);
//open, variable, lossless
type
  { Class TDTS }
  TDTS = class (TObject)
  private
    { Private declarations }
    FFileSize: int64;
    FValid:    boolean;

    FChannels: cardinal;
    FBits:     cardinal;
    FSampleRate: cardinal;

    FBitrate:  word;
    FDuration: double;

    function FGetRatio: double;
    procedure FResetData;

  public
    { Public declarations }
    constructor Create;                                        { Create object }
    destructor Destroy; override;                             { Destroy object }

    function ReadFromFile(const FileName: WideString): boolean;  { Load header }

    property FileSize: int64 Read FFileSize;
    property Valid: boolean Read FValid;

    property Channels: cardinal Read FChannels;
    property Bits: cardinal Read FBits;
    property SampleRate: cardinal Read FSampleRate;

    property Bitrate: word Read FBitrate;
    property Duration: double Read FDuration;
    property Ratio: double Read FGetRatio;             { Compression ratio (%) }
  end;

implementation


{ ********************** Private functions & procedures ********************* }

procedure TDTS.FResetData;
begin
  { Reset all data }
  FFileSize := 0;
  FValid    := False;

  FChannels := 0;
  FBits     := 0;
  FSampleRate := 0;

  FBitrate  := 0;
  FDuration := 0;
end;


{ ********************** Public functions & procedures ********************** }

constructor TDTS.Create;
begin
  { Create object }
  inherited;
  FResetData;
end;

(* -------------------------------------------------------------------------- *)

destructor TDTS.Destroy;
begin
  inherited;
end;

(* -------------------------------------------------------------------------- *)

function TDTS.ReadFromFile(const FileName: WideString): boolean;
var
  f:      TTntFileStream;
  SignatureChunk: cardinal;
  tehWord: word;
  gayDTS: array[0..7] of byte;
begin
  Result := False;
  FResetData;

  f := nil;

  try
    f := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    //0x7FFE8001
    if (f.Read(SignatureChunk, SizeOf(SignatureChunk)) = SizeOf(SignatureChunk)) and
      (SignatureChunk = 25230975) then
      begin
      FillChar(gayDTS, SizeOf(gayDTS), 0);
      f.Seek(3, soFromCurrent);
      f.Read(gayDTS, SizeOf(gayDTS));

      FFileSize := f.Size;
      FValid    := True;

      tehWord := gayDTS[1] or (gayDTS[0] shl 8);

      case ((tehWord and $0FC0) shr 6) of
        0:
          FChannels := 1;
        1..4:
          FChannels := 2;
        5..6:
          FChannels := 3;
        7..8:
          FChannels := 4;
        9:
          FChannels := 5;
        10..12:
          FChannels := 6;
        13:
          FChannels := 7;
        14..15:
          FChannels := 8;
        else
          FChannels := 0;
        end;

      case ((tehWord and $3C) shr 2) of
        1:
          FSampleRate := 8000;
        2:
          FSampleRate := 16000;
        3:
          FSampleRate := 32000;
        6:
          FSampleRate := 11025;
        7:
          FSampleRate := 22050;
        8:
          FSampleRate := 44100;
        11:
          FSampleRate := 12000;
        12:
          FSampleRate := 24000;
        13:
          FSampleRate := 48000;
        else
          FSampleRate := 0;
        end;

      tehWord := 0;
      tehWord := gayDTS[2] or (gayDTS[1] shl 8);

      FBitrate := BIRATES[(tehWord and $03E0) shr 5];

      tehWord := 0;
      tehWord := gayDTS[7] or (gayDTS[6] shl 8);

      case ((tehWord and $01C0) shr 6) of
        0..1:
          FBits := 16;
        2..3:
          FBits := 20;
        4..5:
          FBits := 24;
        else
          FBits := 16;
        end;

      FDuration := FFileSize * 8 / 1000 / FBitrate;

      Result := True;
      end;

  finally
    f.Free;
    end;
end;

(* -------------------------------------------------------------------------- *)

function TDTS.FGetRatio: double;
begin
  { Get compression ratio }
  if FValid then
    Result := FFileSize / ((FDuration * FSampleRate) *
      (FChannels * FBits / 8) + 44) * 100
  else
    Result := 0;
end;

(* -------------------------------------------------------------------------- *)

end.
